import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Queue of HTML files that have yet to be parsed.
 */
public class PageBuffer {
	// INSTANCE FIELDS **********************************************
	/**
	 *  Thread safe Linked List backed Blocking Queue holding html pages.
	 */
	private ConcurrentLinkedQueue<Pair<String, String>> pages;
	
	/**
	 * The PageToRetrieve buffer that we are working with.
	 */
	private PageToRetrieve retbuff;
	
	/**
	 * Is this application threaded?
	 */
	private boolean isThreaded;
	
	/**
	 * The DataGatherer that we are working with.
	 */
	private DataGatherer dgatherer;
	
	/**
	 * List of threads that we are currently executing.
	 */
	private ArrayList<Thread> threads;
	
	/**
	 * Collection of PageParser objects that are associated with each thread in thread list.
	 */
	private ArrayList<PageParser> parsers;
	
	/**
	 * List of keywords to search for.
	 */
	private List<String> keys;
	
	// CONSTRUCTORS *************************************************
	/**
	 * Creates a new PageBuffer.
	 */
	public PageBuffer(PageToRetrieve retbuff) {
		pages = new ConcurrentLinkedQueue<Pair<String, String>>();
		this.retbuff = retbuff;
		threads = new ArrayList<Thread>();
		keys = new ArrayList<String>();
		dgatherer = new DataGatherer(retbuff.getParent().reporter());
		parsers = new ArrayList<PageParser>();
		PageParser temp = new PageParser(this, retbuff, dgatherer);
		parsers.add(temp);
		threads.add(new Thread(temp));
	}
	
	// METHODS ******************************************************
	/**
	 * Executes one cycle of this class.
	 */
	public void tick() {	
		
		if ((pages.size() % 10 == 0 && threads.size() < 5) && isThreaded) {
			PageParser parser = new PageParser(this, retbuff, dgatherer);
			parser.setKeys(keys);
			parsers.add(parser);
			threads.add((new Thread(parser)));
		}		
		for(Thread t : threads){
			t.run();
		}
	}
	
	/**
	 * Sets the threaded mode of the application.
	 * @param threaded True for multithreaded, False for single threaded.
	 */
	public void setThreaded(boolean threaded) {
		isThreaded = threaded;
	}
	
	/**
	 * Sets the keywords we are looking for.
	 * @param keys Keywords to look for.
	 */
	public void setKeys(List<String> keys) {
		this.keys = Collections.unmodifiableList(keys);
		for (PageParser p : parsers) {
			p.setKeys(keys);
		}
	}	
	
	/**
	 * Checks to see if there is another page to be parsed.
	 * @return True if there is another element in the queue
	 */
	public boolean hasNext() {
		return pages.peek() != null ? true : false;
	}

	/**
	 * @return The underlying queue for this buffer.
	 */
	public ConcurrentLinkedQueue<Pair<String, String>> queue() {
		return pages;	
	}
	
	/**
	 * @return The DataGatherer that we are working with.
	 */
	public DataGatherer DataGather() {
		return dgatherer;
	}
}
